<?php

namespace webjson\cron;
use Cron\CronExpression;
use yii\base\InlineAction;
use yii\console\Controller;

/**
 * Created by IntelliJ IDEA.
 * User: wangfangda
 * Date: 2017/3/6
 * Time: 下午5:14
 */
abstract class ScheduleController extends Controller
{

    /**
     * @var array|Event[]
     */
    private $_events = [];

    abstract public function actionRun();

    /**
     * @param $cmd
     *
     * @return Event
     */
    public function command( $cmd )
    {
        $event = new Event( $cmd );
        $this->_events[] = $event;

        return $event;
    }

    //public function afterAction( InlineAction $action, $result )
    public function afterAction($action, $result )
    {
        $cacheKey = \Yii::$app->id . __METHOD__;
        $list = \Yii::$app->cache->get( $cacheKey );
        $now = ( new \DateTime() )->setTimestamp( $_SERVER[ 'REQUEST_TIME' ] );
        $execNow = clone $now;

        if ( !is_array( $list ) )
        {
            $list = [];
        }

        if ( $action->actionMethod == 'actionRun' )
        {
            foreach ( $this->_events as $event )
            {
                $time = $event->getSchedule();
                $cmd = $event->getCommand();

                if ( !empty( $time ) )
                {
                    $lastRunDate = isset( $list[ $cmd ] ) ? $list[ $cmd ] : $now->getTimestamp();

                    $cron = CronExpression::factory( $time );

                    $nextRunDate = $cron->getNextRunDate( $execNow->setTimestamp( $lastRunDate ) );

                    if ( !isset( $list[ $cmd ] ) || $nextRunDate->getTimestamp() <= $now->getTimestamp() )
                    {
                        $list[ $cmd ] = $nextRunDate->getTimestamp();
                        exec( $this->_packCommand( $cmd ) );
                    }
                }
            }

        }

        \Yii::$app->cache->set( $cacheKey, $list );

        return parent::afterAction( $action, $result );
    }

    /**
     * 重新封装命令行
     *
     * @param string $cmd
     *
     * @return string
     */
    private function _packCommand( $cmd )
    {
        $yii = realpath( $_SERVER[ 'argv' ][ 0 ] );
        $new = PHP_BINARY . " $yii " . $cmd;

        if ( strpos( strtolower( PHP_OS ), 'win' ) === 0 )
        {
            $new = "start /b $new";
        } else
        {
            $new .= ' > /dev/null 2>&1 &';
        }

        return $new;
    }

}